home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / tag.c < prev    next >
C/C++ Source or Header  |  1996-06-11  |  35KB  |  1,426 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * Code to handle tags and the tag stack
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "option.h"
  17.  
  18. static int get_tagfname __ARGS((int, char_u    *));
  19.  
  20. #ifdef EMACS_TAGS
  21. static int parse_tag_line __ARGS((char_u *, int,
  22.                       char_u **, char_u **, char_u **, char_u **, char_u **));
  23. static int jumpto_tag __ARGS((char_u *, int, char_u *, char_u *));
  24. #else
  25. static int parse_tag_line __ARGS((char_u *,
  26.                       char_u **, char_u **, char_u **, char_u **, char_u **));
  27. static int jumpto_tag __ARGS((char_u *, char_u *));
  28. #endif
  29. static int test_for_static __ARGS((char_u **, char_u *, char_u *, char_u *));
  30. static char_u *expand_rel_name __ARGS((char_u *fname, char_u *tag_fname));
  31. static void simplify_filename __ARGS((char_u *filename));
  32. #ifdef EMACS_TAGS
  33. static int test_for_current __ARGS((int, char_u *, char_u *, char_u *));
  34. #else
  35. static int test_for_current __ARGS((char_u *, char_u *, char_u *));
  36. #endif
  37.  
  38. static char_u *bottommsg = (char_u *)"at bottom of tag stack";
  39. static char_u *topmsg = (char_u *)"at top of tag stack";
  40.  
  41. /*
  42.  * Jump to tag; handling of tag stack
  43.  *
  44.  * *tag != NUL (:tag): jump to new tag, add to tag stack
  45.  * type == 1 (:pop) || type == 2 (CTRL-T): jump to old position
  46.  * type == 0 (:tag): jump to old tag
  47.  */
  48.     void
  49. do_tag(tag, type, count)
  50.     char_u    *tag;
  51.     int        type;
  52.     int        count;
  53. {
  54.     int             i;
  55.     struct taggy    *tagstack = curwin->w_tagstack;
  56.     int                tagstackidx = curwin->w_tagstackidx;
  57.     int                tagstacklen = curwin->w_tagstacklen;
  58.     int                oldtagstackidx = tagstackidx;
  59.  
  60.     if (*tag != NUL)                        /* new pattern, add to the stack */
  61.     {
  62.         /*
  63.          * if last used entry is not at the top, delete all tag stack entries
  64.          * above it.
  65.          */
  66.         while (tagstackidx < tagstacklen)
  67.             vim_free(tagstack[--tagstacklen].tagname);
  68.  
  69.                 /* if tagstack is full: remove oldest entry */
  70.         if (++tagstacklen > TAGSTACKSIZE)
  71.         {
  72.             tagstacklen = TAGSTACKSIZE;
  73.             vim_free(tagstack[0].tagname);
  74.             for (i = 1; i < tagstacklen; ++i)
  75.                 tagstack[i - 1] = tagstack[i];
  76.             --tagstackidx;
  77.         }
  78.  
  79.         /*
  80.          * put the tag name in the tag stack
  81.          * the position is added below
  82.          */
  83.         tagstack[tagstackidx].tagname = strsave(tag);
  84.     }
  85.     else if (tagstacklen == 0)                    /* empty stack */
  86.     {
  87.         EMSG("tag stack empty");
  88.         goto end_do_tag;
  89.     }
  90.     else if (type)                                /* go to older position */
  91.     {
  92.         if ((tagstackidx -= count) < 0)
  93.         {
  94.             emsg(bottommsg);
  95.             if (tagstackidx + count == 0)
  96.             {
  97.                 /* We did ^T (or <num>^T) from the bottom of the stack */
  98.                 tagstackidx = 0;
  99.                 goto end_do_tag;
  100.             }
  101.             /* We weren't at the bottom of the stack, so jump all the way to
  102.              * the bottom.
  103.              */
  104.             tagstackidx = 0;
  105.         }
  106.         else if (tagstackidx >= tagstacklen)    /* must have been count == 0 */
  107.         {
  108.             emsg(topmsg);
  109.             goto end_do_tag;
  110.         }
  111.         if (tagstack[tagstackidx].fmark.fnum != curbuf->b_fnum)
  112.         {
  113.             /*
  114.              * Jump to other file. If this fails (e.g. because the file was
  115.              * changed) keep original position in tag stack.
  116.              */
  117.             if (buflist_getfile(tagstack[tagstackidx].fmark.fnum,
  118.                  tagstack[tagstackidx].fmark.mark.lnum, GETF_SETMARK) == FAIL)
  119.             {
  120.                 tagstackidx = oldtagstackidx;    /* back to old position */
  121.                 goto end_do_tag;
  122.             }
  123.         }
  124.         else
  125.             curwin->w_cursor.lnum = tagstack[tagstackidx].fmark.mark.lnum;
  126.         curwin->w_cursor.col = tagstack[tagstackidx].fmark.mark.col;
  127.         curwin->w_set_curswant = TRUE;
  128.         goto end_do_tag;
  129.     }
  130.     else                                    /* go to newer pattern */
  131.     {
  132.         if ((tagstackidx += count - 1) >= tagstacklen)
  133.         {
  134.             /*
  135.              * beyond the last one, just give an error message and go to the
  136.              * last one
  137.              */
  138.             tagstackidx = tagstacklen - 1;
  139.             emsg(topmsg);
  140.         }
  141.         else if (tagstackidx < 0)            /* must have been count == 0 */
  142.         {
  143.             emsg(bottommsg);
  144.             tagstackidx = 0;
  145.             goto end_do_tag;
  146.         }
  147.     }
  148.     /*
  149.      * For :tag [arg], remember position before the jump
  150.      */
  151.     if (type == 0)
  152.     {
  153.         tagstack[tagstackidx].fmark.mark = curwin->w_cursor;
  154.         tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum;
  155.     }
  156.     /* curwin will change in the call to find_tags() if ^W^] was used -- webb */
  157.     curwin->w_tagstackidx = tagstackidx;
  158.     curwin->w_tagstacklen = tagstacklen;
  159.     if (find_tags(tagstack[tagstackidx].tagname, NULL, NULL, NULL, FALSE) > 0)
  160.         ++tagstackidx;
  161.  
  162. end_do_tag:
  163.     curwin->w_tagstackidx = tagstackidx;
  164.     curwin->w_tagstacklen = tagstacklen;
  165. }
  166.  
  167. /*
  168.  * Print the tag stack
  169.  */
  170.     void
  171. do_tags()
  172. {
  173.     int                i;
  174.     char_u            *name;
  175.     struct taggy    *tagstack = curwin->w_tagstack;
  176.     int                tagstackidx = curwin->w_tagstackidx;
  177.     int                tagstacklen = curwin->w_tagstacklen;
  178.  
  179.     set_highlight('t');        /* Highlight title */
  180.     start_highlight();
  181.     MSG_OUTSTR("\n  # TO tag      FROM line in file");
  182.     stop_highlight();
  183.     for (i = 0; i < tagstacklen; ++i)
  184.     {
  185.         if (tagstack[i].tagname != NULL)
  186.         {
  187.             name = fm_getname(&(tagstack[i].fmark));
  188.             if (name == NULL)        /* file name not available */
  189.                 continue;
  190.  
  191.             msg_outchar('\n');
  192.             sprintf((char *)IObuff, "%c%2d %-15s %4ld  %s",
  193.                 i == tagstackidx ? '>' : ' ',
  194.                 i + 1,
  195.                 tagstack[i].tagname,
  196.                 tagstack[i].fmark.mark.lnum,
  197.                 name);
  198.             msg_outtrans(IObuff);
  199.         }
  200.         flushbuf();                    /* show one line at a time */
  201.     }
  202.     if (tagstackidx == tagstacklen)        /* idx at top of stack */
  203.         MSG_OUTSTR("\n>");
  204. }
  205.  
  206. /*
  207.  * find_tags() - goto tag or search for tags in tags files
  208.  *
  209.  * If "tag" is not NULL, search for a single tag and jump to it.
  210.  *   return FAIL for failure, OK for success
  211.  * If "tag" is NULL, find all tags matching the regexp given with 'prog'.
  212.  *   return FAIL if search completely failed, OK otherwise.
  213.  *
  214.  * There is a priority in which type of tag is recognized. It is computed
  215.  * from the PRI_ defines below.
  216.  *
  217.  *  6.  A static or global tag with a full matching tag for the current file.
  218.  *  5.  A global tag with a full matching tag for another file.
  219.  *  4.  A static tag with a full matching tag for another file.
  220.  *  2.  A static or global tag with an ignore-case matching tag for the
  221.  *      current file.
  222.  *  1.  A global tag with an ignore-case matching tag for another file.
  223.  *  0.  A static tag with an ignore-case matching tag for another file.
  224.  *
  225.  *  Tags in an emacs-style tags file are always global.
  226.  */
  227. #define PRI_GLOBAL            1        /* global or emacs tag */
  228. #define PRI_CURRENT            2        /* tag for current file */
  229. #define PRI_FULL_MATCH        4        /* case of tag matches */
  230.  
  231.     int
  232. find_tags(tag, prog, num_file, file, help_only)
  233.     char_u        *tag;                /* NULL or tag to search for */
  234.     regexp        *prog;                /* regexp program or NULL */
  235.     int            *num_file;            /* return value: number of matches found */
  236.     char_u        ***file;            /* return value: array of matches found */
  237.     int            help_only;            /* if TRUE: only tags for help files */
  238. {
  239.     FILE       *fp;
  240.     char_u       *lbuf;                    /* line buffer */
  241.     char_u       *tag_fname;                /* name of tag file */
  242.     int            first_file;                /* trying first tag file */
  243.     char_u       *tagname, *tagname_end;    /* name of tag in current line */
  244.     char_u       *fname, *fname_end;        /* fname in current line */
  245.     int            did_open = FALSE;        /* did open a tag file */
  246.     int            stop_searching = FALSE;    /* stop when match found or error */
  247.     int            retval = FAIL;            /* return value */
  248.     int            is_static;                /* current tag line is static */
  249.     int            is_current;                /* file name matches */
  250.     register char_u    *p;
  251. #ifdef EMACS_TAGS
  252.     char_u       *ebuf;                    /* aditional buffer for etag fname */
  253.     int            is_etag;                /* current file is emaces style */
  254. #endif
  255.  
  256. /*
  257.  * Variables used only when "tag" != NULL
  258.  */
  259.     int            taglen = 0;                /* init for GCC */
  260.     int            cmplen;
  261.     int            full_match;
  262.     int            icase_match;
  263.     int            priority;                /* priority of current line */
  264.  
  265.     char_u        *bestmatch_line = NULL;    /* saved line for best match found so
  266.                                             far */
  267.     char_u        *bestmatch_tag_fname = NULL;
  268.                                         /* copy of tag_fname for best match */
  269.     int            bestmatch_priority = 0; /* best match priority */
  270.  
  271. #ifdef EMACS_TAGS
  272.     /*
  273.      * Stack for included emacs-tags file.
  274.      * It has a fixed size, to truncate cyclic includes. jw
  275.      */
  276. # define INCSTACK_SIZE 42
  277.     struct
  278.     {
  279.         FILE    *fp;
  280.         char_u    *tag_fname;
  281.     } incstack[INCSTACK_SIZE];
  282.  
  283.     int            incstack_idx = 0;            /* index in incstack */
  284.     char_u       *bestmatch_ebuf = NULL;        /* copy of ebuf for best match */
  285.     int            bestmatch_is_etag = FALSE;    /* copy of is_etag for best match */
  286. #endif
  287.  
  288. /*
  289.  * Variables used when "tag" == NULL
  290.  */
  291.     char_u    **matches = NULL;            /* array of matches found */
  292.     char_u    **new_matches;
  293.     int        match_limit = 100;            /* max. number of matches stored */
  294.     int        match_count = 0;            /* number of matches found */
  295.     int        i;
  296.     int        help_save;
  297.  
  298.     help_save = curbuf->b_help;
  299. /*
  300.  * Allocate memory for the buffers that are used
  301.  */
  302.     lbuf = alloc(LSIZE);
  303. #ifdef EMACS_TAGS
  304.     ebuf = alloc(LSIZE);
  305. #endif
  306.     tag_fname = alloc(LSIZE + 1);
  307.                                     /* check for out of memory situation */
  308.     if ((tag == NULL && prog == NULL) || lbuf == NULL || tag_fname == NULL
  309. #ifdef EMACS_TAGS
  310.                                                          || ebuf == NULL
  311. #endif
  312.                                                                         )
  313.         goto findtag_end;
  314.     if (tag == NULL)
  315.     {
  316.         matches = (char_u **)alloc((unsigned)(match_limit * sizeof(char_u *)));
  317.         if (matches == NULL)
  318.             goto findtag_end;
  319.     }
  320.  
  321. /*
  322.  * Initialize a few variables
  323.  */
  324.     if (tag != NULL)
  325.     {
  326.         taglen = STRLEN(tag);
  327.         if (p_tl != 0 && taglen > p_tl)        /* adjust for 'taglength' */
  328.             taglen = p_tl;
  329.     }
  330.     else if (help_only)                /* want tags from help file */
  331.         curbuf->b_help = TRUE;
  332.  
  333. /*
  334.  * Try tag file names from tags option one by one.
  335.  */
  336.     for (first_file = TRUE; get_tagfname(first_file, tag_fname) == OK;
  337.                                                             first_file = FALSE)
  338.     {
  339.         /*
  340.          * A file that doesn't exist is silently ignored.
  341.          */
  342.         if ((fp = fopen((char *)tag_fname, "r")) == NULL)
  343.             continue;
  344.         did_open = TRUE;    /* remember that we found at least one file */
  345.  
  346. #ifdef EMACS_TAGS
  347.         is_etag = 0;        /* default is: not emacs style */
  348. #endif
  349.         /*
  350.          * Read and parse the lines in the file one by one
  351.          */
  352.         while (!got_int)
  353.         {
  354.             line_breakcheck();
  355.  
  356.             if (vim_fgets(lbuf, LSIZE, fp))
  357. #ifdef EMACS_TAGS
  358.                 if (incstack_idx)        /* this was an included file */
  359.                 {
  360.                     --incstack_idx;
  361.                     fclose(fp);            /* end of this file ... */
  362.                     fp = incstack[incstack_idx].fp;
  363.                     STRCPY(tag_fname, incstack[incstack_idx].tag_fname);
  364.                     vim_free(incstack[incstack_idx].tag_fname);
  365.                     is_etag = 1;        /* (only etags can include) */
  366.                     continue;            /* ... continue with parent file */
  367.                 }
  368.                 else
  369. #endif
  370.                     break;                            /* end of file */
  371.  
  372. #ifdef EMACS_TAGS
  373.             /*
  374.              * Emacs tags line with CTRL-L: New file name on next line.
  375.              * The file name is followed by a ','.
  376.              */
  377.             if (*lbuf == Ctrl('L'))        /* remember etag filename in ebuf */
  378.             {
  379.                 is_etag = 1;    
  380.                 if (!vim_fgets(ebuf, LSIZE, fp))
  381.                 {
  382.                     for (p = ebuf; *p && *p != ','; p++)
  383.                         ;
  384.                     *p = NUL;
  385.  
  386.                     /* 
  387.                      * atoi(p+1) is the number of bytes before the next ^L
  388.                      * unless it is an include statement.
  389.                      */
  390.                     if (STRNCMP(p + 1, "include", 7) == 0 &&
  391.                                                  incstack_idx < INCSTACK_SIZE)
  392.                     {
  393.                         if ((incstack[incstack_idx].tag_fname =
  394.                                                   strsave(tag_fname)) != NULL)
  395.                         {
  396.                             incstack[incstack_idx].fp = fp;
  397.                             if ((fp = fopen((char *)ebuf, "r")) == NULL)
  398.                             {
  399.                                 fp = incstack[incstack_idx].fp;
  400.                                 vim_free(incstack[incstack_idx].tag_fname);
  401.                             }
  402.                             else
  403.                             {
  404.                                 STRCPY(tag_fname, ebuf);
  405.                                 ++incstack_idx;
  406.                             }
  407.                             is_etag = 0;    /* we can include anything */
  408.                         }
  409.                     }
  410.                 }
  411.                 continue;
  412.             }
  413. #endif
  414.  
  415.             /*
  416.              * Figure out where the different strings are in this line.
  417.              * For "normal" tags: Do a quick check if the tag matches.
  418.              * This speeds up tag searching a lot!
  419.              */
  420.             if (tag != NULL
  421. #ifdef EMACS_TAGS
  422.                             && !is_etag
  423. #endif
  424.                                         )
  425.             {
  426.                 tagname = lbuf;
  427.                 fname = NULL;
  428.                 for (tagname_end = lbuf; *tagname_end &&
  429.                                     !vim_iswhite(*tagname_end); ++tagname_end)
  430.                 {
  431.                     if (*tagname_end == ':')
  432.                     {
  433.                         if (fname == NULL)
  434.                             fname = skipwhite(skiptowhite(tagname_end));
  435.                         if (fnamencmp(lbuf, fname, tagname_end - lbuf) == 0 &&
  436.                                        vim_iswhite(fname[tagname_end - lbuf]))
  437.                             tagname = tagname_end + 1;
  438.                     }
  439.                 }
  440.  
  441.                 /*
  442.                  * Skip this line if the lenght of the tag is different.
  443.                  */
  444.                 cmplen = tagname_end - tagname;
  445.                 if (p_tl != 0 && cmplen > p_tl)        /* adjust for 'taglength' */
  446.                     cmplen = p_tl;
  447.                 if (taglen != cmplen)
  448.                     continue;
  449.  
  450.                 /*
  451.                  * Skip this line if the tag does not match (ignoring case).
  452.                  */
  453.                 if (vim_strnicmp(tagname, tag, (size_t)cmplen))
  454.                     continue;
  455.  
  456.                 /*
  457.                  * This is a useful tag, isolate the filename.
  458.                  */
  459.                 if (fname == NULL)
  460.                     fname = skipwhite(skiptowhite(tagname_end));
  461.                 fname_end = skiptowhite(fname);
  462.                 if (*fname_end == NUL)
  463.                     i = FAIL;
  464.                 else
  465.                     i = OK;
  466.             }
  467.             else
  468.                 i = parse_tag_line(lbuf,
  469. #ifdef EMACS_TAGS
  470.                                    is_etag,
  471. #endif
  472.                             &tagname, &tagname_end, &fname, &fname_end, NULL);
  473.             if (i == FAIL)
  474.             {
  475.                 EMSG2("Format error in tags file \"%s\"", tag_fname);
  476.                 stop_searching = TRUE;
  477.                 break;
  478.             }
  479.  
  480. #ifdef EMACS_TAGS
  481.             is_static = FALSE;
  482.             if (!is_etag)        /* emacs tags are never static */
  483. #endif
  484.                 is_static = test_for_static(&tagname, tagname_end, 
  485.                                                             fname, fname_end);
  486. #ifdef EMACS_TAGS
  487.             if (is_etag)
  488.                 fname = ebuf;
  489. #endif
  490.             /*
  491.              * "tag" == NULL: find tags matching regexp "prog"
  492.              */
  493.             if (tag == NULL)
  494.             {
  495.                 *tagname_end = NUL;
  496.                 if (vim_regexec(prog, tagname, TRUE))
  497.                 {
  498.                     is_current = test_for_current(
  499. #ifdef EMACS_TAGS
  500.                             is_etag,
  501. #endif
  502.                                      fname, fname_end, tag_fname);
  503.                     if (!is_static || is_current)
  504.                     {
  505.                         /*
  506.                          * Found a match, add it to matches[].
  507.                          * May need to make matches[] larger.
  508.                          */
  509.                         if (match_count == match_limit)
  510.                         {
  511.                             match_limit += 100;
  512.                             new_matches = (char_u **)alloc(
  513.                                     (unsigned)(match_limit * sizeof(char_u *)));
  514.                             if (new_matches == NULL)
  515.                             {
  516.                                 /* Out of memory! Just forget about the rest
  517.                                  * of the matches. */
  518.                                 retval = OK;
  519.                                 stop_searching = TRUE;
  520.                                 break;
  521.                             }
  522.                             for (i = 0; i < match_count; i++)
  523.                                 new_matches[i] = matches[i];
  524.                             vim_free(matches);
  525.                             matches = new_matches;
  526.                         }
  527.                         if (help_only)
  528.                         {
  529.                             int        len;
  530.  
  531.                             /*
  532.                              * Append the help-heuristic number after the
  533.                              * tagname, for sorting it later.
  534.                              */
  535.                             len = STRLEN(tagname);
  536.                             p = alloc(len + 10);
  537.                             if (p != NULL)
  538.                             {
  539.                                 STRCPY(p, tagname);
  540.                                 sprintf((char *)p + len + 1, "%06d",
  541.                                                        help_heuristic(tagname,
  542.                                            (int)(prog->startp[0] - tagname)));
  543.                             }
  544.                             matches[match_count++] = p;
  545.                         }
  546.                         else
  547.                             matches[match_count++] = strsave(tagname);
  548.                     }
  549.                 }
  550.             }
  551.             /*
  552.              * "tag" != NULL: find tag and jump to it
  553.              */
  554.             else
  555.             {
  556.                 /*
  557.                  * If tag length does not match, skip the rest
  558.                  */
  559.                 cmplen = tagname_end - tagname;
  560.                 if (p_tl != 0 && cmplen > p_tl)        /* adjust for 'taglength' */
  561.                     cmplen = p_tl;
  562.                 if (taglen == cmplen)
  563.                 {
  564.                     /*
  565.                      * Check for match (ignoring case).
  566.                      */
  567.                     icase_match = (vim_strnicmp(tagname, tag,
  568.                                                         (size_t)cmplen) == 0);
  569.                     if (icase_match)    /* Tag matches somehow */
  570.                     {
  571.                         /*
  572.                          * If it's a full match for the current file, jump to
  573.                          * it now.
  574.                          */
  575.                         full_match = (STRNCMP(tagname, tag, cmplen) == 0);
  576.                         is_current = test_for_current(
  577. #ifdef EMACS_TAGS
  578.                                 is_etag,
  579. #endif
  580.                                          fname, fname_end, tag_fname);
  581.                         if (full_match && is_current)
  582.                         {
  583.                             retval = jumpto_tag(lbuf,
  584. #ifdef EMACS_TAGS
  585.                                                     is_etag, ebuf,
  586. #endif
  587.                                                                    tag_fname);
  588.                             stop_searching = TRUE;
  589.                             break;
  590.                         }
  591.  
  592.                         /*
  593.                          * If the priority of the current line is higher than
  594.                          * the best match so far, store it as the best match
  595.                          */
  596.                         if (full_match)
  597.                             priority = PRI_FULL_MATCH;
  598.                         else
  599.                             priority = 0;
  600.                         if (is_current)
  601.                             priority += PRI_CURRENT;
  602.                         if (!is_static)
  603.                             priority += PRI_GLOBAL;
  604.  
  605.                         if (priority > bestmatch_priority)
  606.                         {
  607.                             vim_free(bestmatch_line);
  608.                             bestmatch_line = strsave(lbuf);
  609.                             vim_free(bestmatch_tag_fname);
  610.                             bestmatch_tag_fname = strsave(tag_fname);
  611.                             bestmatch_priority = priority;
  612. #ifdef EMACS_TAGS
  613.                             bestmatch_is_etag = is_etag;
  614.                             if (is_etag)
  615.                             {
  616.                                 vim_free(bestmatch_ebuf);
  617.                                 bestmatch_ebuf = strsave(ebuf);
  618.                             }
  619. #endif
  620.                         }
  621.                     }
  622.                 }
  623.             }
  624.         }
  625.         fclose(fp);
  626. #ifdef EMACS_TAGS
  627.         while (incstack_idx)
  628.         {
  629.             --incstack_idx;
  630.             fclose(incstack[incstack_idx].fp);
  631.             vim_free(incstack[incstack_idx].tag_fname);
  632.         }
  633. #endif
  634.         if (stop_searching)
  635.             break;
  636.  
  637.         /*
  638.          * Stop searching if a tag was found in the current tags file and
  639.          * we got a global match with matching case or 'ignorecase' is set.
  640.          */
  641.         if (tag != NULL && bestmatch_line != NULL &&
  642.                bestmatch_priority >= (p_ic ? 0 : PRI_FULL_MATCH) + PRI_GLOBAL)
  643.             break;
  644.     }
  645.  
  646.     if (!stop_searching)
  647.     {
  648.         if (!did_open)                        /* never opened any tags file */
  649.             EMSG("No tags file");
  650.         else if (tag == NULL)
  651.         {
  652.             retval = OK;        /* It's OK even when no tag found */
  653.         }
  654.         else
  655.         {
  656.             /*
  657.              * If we didn't find a static full match, use the best match found.
  658.              */
  659.             if (bestmatch_line != NULL)
  660.             {
  661.                 if (bestmatch_priority < PRI_FULL_MATCH)
  662.                 {
  663.                     MSG("Only found tag with different case!");
  664.                     if (!msg_scrolled)
  665.                     {
  666.                         flushbuf();
  667.                         mch_delay(1000L, TRUE);
  668.                     }
  669.                 }
  670.                 retval = jumpto_tag(bestmatch_line,
  671. #ifdef EMACS_TAGS
  672.                         bestmatch_is_etag, bestmatch_ebuf,
  673. #endif
  674.                         bestmatch_tag_fname);
  675.             }
  676.             else
  677.                 EMSG("tag not found");
  678.         }
  679.     }
  680.  
  681. findtag_end:
  682.     vim_free(lbuf);
  683.     vim_free(tag_fname);
  684.     vim_free(bestmatch_line);
  685.     vim_free(bestmatch_tag_fname);
  686. #ifdef EMACS_TAGS
  687.     vim_free(ebuf);
  688.     vim_free(bestmatch_ebuf);
  689. #endif
  690.  
  691.     if (tag == NULL)
  692.     {
  693.         if (retval == FAIL)            /* free all matches found */
  694.             while (match_count > 0)
  695.                 vim_free(matches[--match_count]);
  696.         if (match_count == 0)        /* nothing found, free matches[] */
  697.         {
  698.             vim_free(matches);
  699.             matches = NULL;
  700.         }
  701.         *file = matches;
  702.         *num_file = match_count;
  703.     }
  704.     curbuf->b_help = help_save;
  705.  
  706.     return retval;
  707. }
  708.  
  709. /*
  710.  * Get the next name of a tag file from the tag file list.
  711.  * For help files, use "vim_tags" file only.
  712.  *
  713.  * Return FAIL if no more tag file names, OK otherwise.
  714.  */
  715.     static int
  716. get_tagfname(first, buf)
  717.     int        first;            /* TRUE when first file name is wanted */
  718.     char_u    *buf;            /* pointer to buffer of LSIZE chars */
  719. {
  720.     static char_u    *np = NULL;
  721.     char_u            *fname;
  722.     size_t            path_len, fname_len;
  723.     /*
  724.      * A list is made of the files that have been visited.
  725.      */
  726.     struct visited
  727.     {
  728.         struct visited    *v_next;
  729. #if defined(UNIX)
  730.         struct stat        v_st;
  731. #else
  732.         char_u            v_fname[1];        /* actually longer */
  733. #endif
  734.     };
  735.     static struct visited    *first_visited = NULL;
  736.     struct visited            *vp;
  737. #if defined(UNIX)
  738.     struct stat                st;
  739. #endif
  740.  
  741.     if (first)
  742.     {
  743.         np = p_tags;
  744.         while (first_visited != NULL)
  745.         {
  746.             vp = first_visited->v_next;
  747.             vim_free(first_visited);
  748.             first_visited = vp;
  749.         }
  750.     }
  751.  
  752.     if (np == NULL)            /* tried allready (or bogus call) */
  753.         return FAIL;
  754.  
  755.     /*
  756.      * For a help window only try the file 'vim_tags' in the same
  757.      * directory as 'helpfile'.
  758.      */
  759.     if (curbuf->b_help)
  760.     {
  761.         path_len = gettail(p_hf) - p_hf;
  762.         if (path_len + 9 >= LSIZE)
  763.             return FAIL;
  764.         vim_memmove(buf, p_hf, path_len);
  765.         STRCPY(buf + path_len, "vim_tags");
  766.  
  767.         np = NULL;                /* try only once */
  768.     }
  769.  
  770.     else
  771.     {
  772.         /*
  773.          * Loop until we have found a file name that can be used.
  774.          */
  775.         for (;;)
  776.         {
  777.             if (*np == NUL)            /* tried all possibilities */
  778.                 return FAIL;
  779.  
  780.             /*
  781.              * Copy next file name into buf.
  782.              */
  783.             (void)copy_option_part(&np, buf, LSIZE, " ,");
  784.  
  785.             /*
  786.              * Tag file name starting with "./": Replace '.' with path of
  787.              * current file.
  788.              */
  789.             if (buf[0] == '.' && ispathsep(buf[1]))
  790.             {
  791.                 if (curbuf->b_filename == NULL)    /* skip if no filename */
  792.                     continue;
  793.  
  794.                 path_len = gettail(curbuf->b_filename) - curbuf->b_filename;
  795.                 fname = buf + 1;
  796.                 while (ispathsep(*fname))        /* skip '/' and the like */
  797.                     ++fname;
  798.                 fname_len = STRLEN(fname);
  799.                 if (fname_len + path_len + 1 > LSIZE)
  800.                     continue;
  801.                 vim_memmove(buf + path_len, fname, fname_len + 1);
  802.                 vim_memmove(buf, curbuf->b_filename, path_len);
  803.             }
  804.  
  805.             /*
  806.              * Check if this tags file has been used already.
  807.              * If file doesn't exist, skip it.
  808.              */
  809. #if defined(UNIX)
  810.             if (stat((char *)buf, &st) < 0)
  811. #else
  812.             if (FullName(buf, NameBuff, MAXPATHL, TRUE) == FAIL)
  813. #endif
  814.                 continue;
  815.  
  816.             for (vp = first_visited; vp != NULL; vp = vp->v_next)
  817. #if defined(UNIX)
  818.                 if (vp->v_st.st_dev == st.st_dev &&
  819.                                                  vp->v_st.st_ino == st.st_ino)
  820. #else
  821.                 if (fnamecmp(vp->v_fname, NameBuff) == 0)
  822. #endif
  823.                     break;
  824.  
  825.             if (vp != NULL)            /* already visited, skip it */
  826.                 continue;
  827.  
  828.             /*
  829.              * Found the next name.  Add it to the list of visited files.
  830.              */
  831. #if defined(UNIX)
  832.             vp = (struct visited *)alloc((unsigned)sizeof(struct visited));
  833. #else
  834.             vp = (struct visited *)alloc((unsigned)(sizeof(struct visited) +
  835.                                                            STRLEN(NameBuff)));
  836. #endif
  837.             if (vp != NULL)
  838.             {
  839. #if defined(UNIX)
  840.                 vp->v_st = st;
  841. #else
  842.                 STRCPY(vp->v_fname, NameBuff);
  843. #endif
  844.                 vp->v_next = first_visited;
  845.                 first_visited = vp;
  846.             }
  847.             break;
  848.         }
  849.     }
  850.     return OK;
  851. }
  852.  
  853. /*
  854.  * Parse one line from the tags file. Find start/end of tag name, start/end of
  855.  * file name and start of search pattern.
  856.  *
  857.  * If is_etag is TRUE, fname and fname_end are not set.
  858.  * If command == NULL it is not set.
  859.  *
  860.  * Return FAIL if there is a format error in this line, OK otherwise.
  861.  */
  862.     static int
  863. parse_tag_line(lbuf,
  864. #ifdef EMACS_TAGS
  865.                     is_etag,
  866. #endif
  867.                               tagname, tagname_end, fname, fname_end, command)
  868.     char_u        *lbuf;
  869. #ifdef EMACS_TAGS
  870.     int            is_etag;
  871. #endif
  872.     char_u        **tagname;
  873.     char_u        **tagname_end;
  874.     char_u        **fname;
  875.     char_u        **fname_end;
  876.     char_u        **command;
  877. {
  878.     char_u        *p;
  879.  
  880. #ifdef EMACS_TAGS
  881.     char_u        *p_7f;
  882.  
  883.     if (is_etag)
  884.     {
  885.         /*
  886.          * There are two formats for an emacs tag line:
  887.          * 1:  struct EnvBase ^?EnvBase^A139,4627
  888.          * 2: #define    ARPB_WILD_WORLD ^?153,5194
  889.          */
  890.         p_7f = vim_strchr(lbuf, 0x7f);
  891.         if (p_7f == NULL)
  892.             return FAIL;
  893.                                         /* find start of line number */
  894.         for (p = p_7f + 1; *p < '0' || *p > '9'; ++p)
  895.             if (*p == NUL)
  896.                 return FAIL;
  897.         if (command != NULL)
  898.             *command = p;
  899.  
  900.                                 /* first format: explicit tagname given */
  901.         if (p[-1] == Ctrl('A'))
  902.         {
  903.             *tagname = p_7f + 1;
  904.             *tagname_end = p - 1;
  905.         }
  906.         else
  907.                                 /* second format: isolate tagname */
  908.         {
  909.             /* find end of tagname */
  910.             for (p = p_7f - 1; *p == ' ' || *p == '\t' || 
  911.                                                   *p == '(' || *p == ';'; --p)
  912.                 if (p == lbuf)
  913.                     return FAIL;
  914.             *tagname_end = p + 1;
  915.             while (p >= lbuf && *p != ' ' && *p != '\t')
  916.                 --p;
  917.             *tagname = p + 1;
  918.         }
  919.     }
  920.     else
  921.     {
  922. #endif
  923.             /* Isolate the tagname, from lbuf up to the first white */
  924.         *tagname = lbuf;
  925.         p = skiptowhite(lbuf);
  926.         if (*p == NUL)
  927.             return FAIL;
  928.         *tagname_end = p;
  929.  
  930.             /* Isolate file name, from first to second white space */
  931.         p = skipwhite(p);
  932.         *fname = p;
  933.         p = skiptowhite(p);
  934.         if (*p == NUL)
  935.             return FAIL;
  936.         *fname_end = p;
  937.  
  938.             /* find start of search command, after second white space */
  939.         if (command != NULL)
  940.         {
  941.             p = skipwhite(p);
  942.             if (*p == NUL)
  943.                 return FAIL;
  944.             *command = p;
  945.         }
  946. #ifdef EMACS_TAGS
  947.     }
  948. #endif
  949.  
  950.     return OK;
  951. }
  952.  
  953. /*
  954.  * Check if tagname is a static tag
  955.  *
  956.  * Static tags produced by the ctags program have the
  957.  * format: 'file:tag  file  /pattern'.
  958.  * This is only recognized when both occurences of 'file'
  959.  * are the same, to avoid recognizing "string::string" or
  960.  * ":exit".
  961.  *
  962.  * Return TRUE if it is a static tag and adjust *tagname to the real tag.
  963.  * Return FALSE if it is not a static tag.
  964.  */
  965.     static int
  966. test_for_static(tagname, tagname_end, fname, fname_end)
  967.     char_u        **tagname;
  968.     char_u        *tagname_end;
  969.     char_u        *fname;
  970.     char_u        *fname_end;
  971. {
  972.     char_u        *p;
  973.  
  974.     p = *tagname + (fname_end - fname);
  975.     if (p < tagname_end && *p == ':' &&
  976.                             fnamencmp(*tagname, fname, fname_end - fname) == 0)
  977.     {
  978.         *tagname = p + 1;
  979.         return TRUE;
  980.     }
  981.     return FALSE;
  982. }
  983.  
  984. /*
  985.  * Jump to a tag that has been found in one of the tag files
  986.  */
  987.     static int
  988. jumpto_tag(lbuf,
  989. #ifdef EMACS_TAGS
  990.                 is_etag, etag_fname,
  991. #endif
  992.                                     tag_fname)
  993.     char_u        *lbuf;            /* line from the tags file for this tag */
  994. #ifdef EMACS_TAGS
  995.     int            is_etag;        /* TRUE if it's from an emacs tags file */
  996.     char_u        *etag_fname;    /* file name for tag if is_etag is TRUE */
  997. #endif
  998.     char_u        *tag_fname;        /* file name of the tags file itself */
  999. {
  1000.     int            save_secure;
  1001.     int            save_p_ws, save_p_scs, save_p_ic;
  1002.     char_u        *str;
  1003.     char_u        *pbuf;                    /* search pattern buffer */
  1004.     char_u        *p;
  1005.     char_u        *expanded_fname = NULL;
  1006.     char_u        *tagname, *tagname_end;
  1007.     char_u        *fname, *fname_end;
  1008.     char_u        *orig_fname;
  1009.     int            retval = FAIL;
  1010.     int            getfile_result;
  1011.     int            search_options;
  1012.  
  1013.     pbuf = alloc(LSIZE);
  1014.  
  1015.     if (pbuf == NULL
  1016. #ifdef EMACS_TAGS
  1017.                     || (is_etag && etag_fname == NULL)
  1018. #endif
  1019.                                                         || tag_fname == NULL)
  1020.         goto erret;
  1021.  
  1022.     /*
  1023.      * find the search pattern (caller should check it is there)
  1024.      */
  1025.     if (parse_tag_line(lbuf,
  1026. #ifdef EMACS_TAGS
  1027.                                is_etag,
  1028. #endif
  1029.                     &tagname, &tagname_end, &fname, &fname_end, &str) == FAIL)
  1030.         goto erret;
  1031.     orig_fname = fname;        /* remember for test_for_static() below */
  1032.  
  1033. #ifdef EMACS_TAGS
  1034.     if (is_etag)
  1035.         fname = etag_fname;
  1036.     else
  1037. #endif
  1038.         *fname_end = NUL;
  1039.  
  1040.     /*
  1041.      * If the command is a string like "/^function fname"
  1042.      * scan through the search string. If we see a magic
  1043.      * char, we have to quote it. This lets us use "real"
  1044.      * implementations of ctags.
  1045.      */
  1046.     if (*str == '/' || *str == '?')
  1047.     {
  1048.         p = pbuf;
  1049.         *p++ = *str++;            /* copy the '/' or '?' */
  1050.         if (*str == '^')
  1051.             *p++ = *str++;            /* copy the '^' */
  1052.  
  1053.         while (*str)
  1054.         {
  1055.             switch (*str)
  1056.             {
  1057.                         /* Always remove '\' before '('.
  1058.                          * Remove a '\' befor '*' if 'nomagic'.
  1059.                          * Otherwise just copy the '\' and don't look at the
  1060.                          * next character
  1061.                          */
  1062.             case '\\':    if (str[1] == '(' || (!p_magic && str[1] == '*'))
  1063.                             ++str;
  1064.                         else
  1065.                             *p++ = *str++;
  1066.                         break;
  1067.  
  1068.             case '\r':
  1069.             case '\n':    *str = pbuf[0];    /* copy '/' or '?' */
  1070.                         str[1] = NUL;    /* delete NL after CR */
  1071.                         break;
  1072.  
  1073.                         /*
  1074.                          * if string ends in search character: skip it
  1075.                          * else escape it with '\'
  1076.                          */
  1077.             case '/':
  1078.             case '?':    if (*str != pbuf[0])    /* not the search char */
  1079.                             break;
  1080.                                                 /* last char */
  1081.                         if (str[1] == '\n' || str[1] == '\r')
  1082.                         {
  1083.                             ++str;
  1084.                             continue;
  1085.                         }
  1086.             case '[':
  1087.                         if (!p_magic)
  1088.                             break;
  1089.             case '^':
  1090.             case '*':
  1091.             case '~':
  1092.             case '.':    *p++ = '\\';
  1093.                         break;
  1094.             }
  1095.             *p++ = *str++;
  1096.         }
  1097.     }
  1098.     else        /* not a search command, just copy it */
  1099.     {
  1100.         for (p = pbuf; *str && *str != '\n'; )
  1101.         {
  1102. #ifdef EMACS_TAGS
  1103.             if (is_etag && *str == ',')        /* stop at ',' after line number */
  1104.                 break;
  1105. #endif
  1106.             *p++ = *str++;
  1107.         }
  1108.     }
  1109.     *p = NUL;
  1110.  
  1111.     /*
  1112.      * expand filename (for environment variables)
  1113.      */
  1114.     expanded_fname = ExpandOne((char_u *)fname, NULL, WILD_LIST_NOTFOUND,
  1115.                                                             WILD_EXPAND_FREE);
  1116.     if (expanded_fname != NULL)
  1117.         fname = expanded_fname;
  1118.  
  1119.     /*
  1120.      * if 'tagrelative' option set, may change file name
  1121.      */
  1122.     fname = expand_rel_name(fname, tag_fname);
  1123.  
  1124.     /*
  1125.      * check if file for tag exists before abandoning current file
  1126.      */
  1127.     if (getperm(fname) < 0)
  1128.     {
  1129.         EMSG2("File \"%s\" does not exist", fname);
  1130.         goto erret;
  1131.     }
  1132.  
  1133.     ++RedrawingDisabled;
  1134.     /*
  1135.      * if it was a CTRL-W CTRL-] command split window now
  1136.      */
  1137.     if (postponed_split)
  1138.         win_split(0, FALSE);
  1139.     /*
  1140.      * A :ta from a help file will keep the b_help flag set.
  1141.      */
  1142.     keep_help_flag = curbuf->b_help;
  1143.     getfile_result = getfile(0, fname, NULL, TRUE, (linenr_t)0);
  1144.  
  1145.     if (getfile_result <= 0)            /* got to the right file */
  1146.     {
  1147.         curwin->w_set_curswant = TRUE;
  1148.         postponed_split = FALSE;
  1149.  
  1150.         save_secure = secure;
  1151.         secure = 1;
  1152.         /*
  1153.          * If 'cpoptions' contains 't', store the search pattern for the "n"
  1154.          * command.  If 'cpoptions' does not contain 't', the search pattern
  1155.          * is not stored.
  1156.          */
  1157.         if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL)
  1158.             search_options = 0;
  1159.         else
  1160.             search_options = SEARCH_KEEP;
  1161.  
  1162.         /*
  1163.          * if the command is a search, try here
  1164.          *
  1165.          * Rather than starting at line one, just turn wrap-scan
  1166.          * on temporarily, this ensures that tags on line 1 will
  1167.          * be found, and makes sure our guess searches search the
  1168.          * whole file when repeated -- webb.
  1169.          * Also reset 'smartcase' for the search, since the search
  1170.          * pattern was not typed by the user.
  1171.          */
  1172.         if (pbuf[0] == '/' || pbuf[0] == '?')
  1173.         {
  1174.             save_p_ws = p_ws;
  1175.             save_p_ic = p_ic;
  1176.             save_p_scs = p_scs;
  1177.             p_ws = TRUE;    /* Switch wrap-scan on temporarily */
  1178.             p_ic = FALSE;    /* don't ignore case now */
  1179.             p_scs = FALSE;
  1180.             add_to_history(1, pbuf + 1);    /* put pattern in search history */
  1181.  
  1182.             if (do_search(pbuf[0], pbuf + 1, (long)1, search_options))
  1183.                 retval = OK;
  1184.             else
  1185.             {
  1186.                 register int notfound = FALSE;
  1187.  
  1188.                 /*
  1189.                  * try again, ignore case now
  1190.                  */
  1191.                 p_ic = TRUE;
  1192.                 if (!do_search(pbuf[0], pbuf + 1, (long)1, search_options))
  1193.                 {
  1194.                     /*
  1195.                      * Failed to find pattern, take a guess: "^func  ("
  1196.                      */
  1197.                     (void)test_for_static(&tagname, tagname_end,
  1198.                                                         orig_fname, fname_end);
  1199.                     *tagname_end = NUL;
  1200.                     sprintf((char *)pbuf, "^%s[ \t]*(", tagname);
  1201.                     if (!do_search('/', pbuf, (long)1, search_options))
  1202.                     {
  1203.                         /* Guess again: "^char * func  (" */
  1204.                         sprintf((char *)pbuf, "^[#a-zA-Z_].*%s[ \t]*(",
  1205.                                                                      tagname);
  1206.                         if (!do_search('/', pbuf, (long)1, search_options))
  1207.                             notfound = TRUE;
  1208.                     }
  1209.                 }
  1210.                 if (notfound)
  1211.                     EMSG("Can't find tag pattern");
  1212.                 else
  1213.                 {
  1214.                     MSG("Couldn't find tag, just guessing!");
  1215.                     if (!msg_scrolled)
  1216.                     {
  1217.                         flushbuf();
  1218.                         mch_delay(1000L, TRUE);
  1219.                     }
  1220.                     retval = OK;
  1221.                 }
  1222.             }
  1223.             p_ws = save_p_ws;
  1224.             p_ic = save_p_ic;
  1225.             p_scs = save_p_scs;
  1226.         }
  1227.         else
  1228.         {                            /* start command in line 1 */
  1229.             curwin->w_cursor.lnum = 1;
  1230.             do_cmdline(pbuf, TRUE, TRUE);
  1231.             retval = OK;
  1232.         }
  1233.  
  1234.         if (secure == 2)            /* done something that is not allowed */
  1235.             wait_return(TRUE);
  1236.         secure = save_secure;
  1237.  
  1238.         /*
  1239.          * Print the file message after redraw if jumped to another file.
  1240.          * Don't do this for help files (avoid a hit-return message).
  1241.          */
  1242.         if (getfile_result == -1)
  1243.         {
  1244.             if (!curbuf->b_help)
  1245.                 need_fileinfo = TRUE;
  1246.             retval = OK;            /* always return OK if jumped to another
  1247.                                        file (at least we found the file!) */
  1248.         }
  1249.  
  1250.         /*
  1251.          * For a help buffer: Put the cursor line at the top of the window,
  1252.          * the help subject will be below it.
  1253.          */
  1254.         if (curbuf->b_help)
  1255.         {
  1256.             curwin->w_topline = curwin->w_cursor.lnum;
  1257.             comp_Botline(curwin);
  1258.             cursupdate();        /* take care of 'scrolloff' */
  1259.             updateScreen(NOT_VALID);
  1260.         }
  1261.         --RedrawingDisabled;
  1262.     }
  1263.     else
  1264.     {
  1265.         --RedrawingDisabled;
  1266.         if (postponed_split)            /* close the window */
  1267.         {
  1268.             close_window(curwin, FALSE);
  1269.             postponed_split = FALSE;
  1270.         }
  1271.     }
  1272.  
  1273. erret:
  1274.     vim_free(pbuf);
  1275.     vim_free(expanded_fname);
  1276.  
  1277.     return retval;
  1278. }
  1279.  
  1280. /*
  1281.  * If 'tagrelative' option set, change fname (name of file containing tag)
  1282.  * according to tag_fname (name of tag file containing fname).
  1283.  */
  1284.     static char_u *
  1285. expand_rel_name(fname, tag_fname)
  1286.     char_u        *fname;
  1287.     char_u        *tag_fname;
  1288. {
  1289.     char_u        *p;
  1290.  
  1291.     if ((p_tr || curbuf->b_help) && !isFullName(fname) &&
  1292.                                        (p = gettail(tag_fname)) != tag_fname)
  1293.     {
  1294.         STRCPY(NameBuff, tag_fname);
  1295.         STRNCPY(NameBuff + (p - tag_fname), fname,
  1296.                                                  MAXPATHL - (p - tag_fname));
  1297.         /*
  1298.          * Translate names like "src/a/../b/file.c" into "src/b/file.c".
  1299.          */
  1300.         simplify_filename(NameBuff);
  1301.         fname = NameBuff;
  1302.     }
  1303.     return fname;
  1304. }
  1305.  
  1306. /*
  1307.  * Moves the tail part of the path (including the terminating NUL) pointed to
  1308.  * by "tail" to the new location pointed to by "here". This should accomodate
  1309.  * an overlapping move.
  1310.  */
  1311. #define movetail(here, tail)  vim_memmove(here, tail, STRLEN(tail) + (size_t)1)
  1312.  
  1313. /*
  1314.  * For MS-DOS we should check for backslash too, but that is complicated.
  1315.  */
  1316. #define DIR_SEP        '/'            /* the directory separator character */
  1317.  
  1318. /*
  1319.  * Converts a filename into a canonical form. It simplifies a filename into
  1320.  * its simplest form by stripping out unneeded components, if any.  The
  1321.  * resulting filename is simplified in place and will either be the same
  1322.  * length as that supplied, or shorter.
  1323.  */
  1324.     static void
  1325. simplify_filename(filename)
  1326.     char_u *filename;
  1327. {
  1328.     int        absolute = FALSE;
  1329.     int        components = 0;
  1330.     char_u    *p, *tail;
  1331.  
  1332.     p = filename;
  1333.     if (*p == DIR_SEP)
  1334.     {
  1335.         absolute = TRUE;
  1336.         ++p;
  1337.     }
  1338.     do
  1339.     {
  1340.         /*  Always leave "p" pointing to character following next "/". */
  1341.         if (*p == DIR_SEP)
  1342.             movetail(p, p+1);                /* strip duplicate "/" */
  1343.         else if (STRNCMP(p, "./", 2) == 0)
  1344.             movetail(p, p+2);                /* strip "./" */
  1345.         else if (STRNCMP(p, "../", 3) == 0)
  1346.         {
  1347.             if (components > 0)                /* strip any prev. component */
  1348.             {
  1349.                 *(p - 1) = 0;                /* delete "/" before  "../" */
  1350.                 tail  = p + 2;                /* skip to "/" of "../" */
  1351.                 p = vim_strrchr(filename, DIR_SEP);     /* find preceding sep. */
  1352.                 if (p != NULL)                /* none found */
  1353.                     ++p;                    /* skip to char after "/" */
  1354.                 else
  1355.                 {
  1356.                     ++tail;                    /* strip leading "/" from tail*/
  1357.                     p = filename;            /* go back to beginning */
  1358.                     if (absolute)            /* skip over any leading "/" */
  1359.                         ++p;
  1360.                 }
  1361.                 movetail(p, tail);            /* strip previous component */
  1362.                 --components;
  1363.             }
  1364.             else if (absolute)                /* no parent to root... */
  1365.                 movetail(p, p+3);            /*   so strip "../" */
  1366.             else                            /* leading series of "../" */
  1367.             {
  1368.                 p = vim_strchr(p, DIR_SEP);    /* skip to next "/" */
  1369.                 if (p != NULL)
  1370.                     ++p;                    /* skip to char after "/" */
  1371.             }
  1372.         }
  1373.         else
  1374.         {
  1375.             ++components;                    /* simple path component */
  1376.             p = vim_strchr(p, DIR_SEP);            /* skip to next "/" */
  1377.             if (p != NULL)
  1378.                 ++p;                        /* skip to char after "/" */
  1379.         }
  1380.     } while (p != NULL && *p != NUL);
  1381. }
  1382.  
  1383. /*
  1384.  * Check if we have a tag for the current file.
  1385.  * This is a bit slow, because of the full path compare in fullpathcmp().
  1386.  * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current
  1387.  * file.
  1388.  */
  1389.     static int
  1390. #ifdef EMACS_TAGS
  1391. test_for_current(is_etag, fname, fname_end, tag_fname)
  1392.     int        is_etag;
  1393. #else
  1394. test_for_current(fname, fname_end, tag_fname)
  1395. #endif
  1396.     char_u    *fname;
  1397.     char_u    *fname_end;
  1398.     char_u    *tag_fname;
  1399. {
  1400.     int        c;
  1401.     int        retval;
  1402.  
  1403.     if (curbuf->b_filename == NULL)
  1404.         retval = FALSE;
  1405.     else
  1406.     {
  1407. #ifdef EMACS_TAGS
  1408.         if (is_etag)
  1409.             c = 0;            /* to shut up GCC */
  1410.         else
  1411. #endif
  1412.         {
  1413.             c = *fname_end;
  1414.             *fname_end = NUL;
  1415.         }
  1416.         retval = (fullpathcmp(expand_rel_name(fname, tag_fname),
  1417.                                             curbuf->b_xfilename) == FPC_SAME);
  1418. #ifdef EMACS_TAGS
  1419.         if (!is_etag)
  1420. #endif
  1421.             *fname_end = c;
  1422.     }
  1423.  
  1424.     return retval;
  1425. }
  1426.